import { Ast, Visitor, createRootAst } from "./ast";
import { IsMineProfileAvatarSettingPage, isHomeFollowPage, isHomeJingXuanPage, isHomePage, isLiveRoomPage, isLiveSquarePage, isMenuPage, isMineMoneyPage, isMinePage, isMineProfileAvatarUploadPage, isMineProfileBgSettingPage, isMineProfileBgUploadPage, isMineProfileNicknameSettingPage, isMineProfilePage, isMyFollowPage, isSettingCachePage, isSettingPage, isTabLayoutPage } from "./pages";
import { kwaiLiveMyFollow } from "./schema";
import { PACKAGES, tryRun } from "./utils";
/**
 * 去某个页面的Visitor
 */
export interface ToContext {
    to?: () => void;
    up?: () => void;
}
export abstract class ToVisitor implements Visitor<ToContext>{
    visitNode(node: Ast, ctx: ToContext) {
        if (ctx.to) return;
        if (!node.visibleToUser) return;
        if (node.className) {
            const classNameSplit = node.className.split('.')
            const classNameEnd = classNameSplit.pop()
            const methodName = `visit${classNameEnd.charAt(0).toUpperCase() + classNameEnd.slice(1)}`
            if (this[methodName]) return this[methodName](node, ctx)
        }
        node.children.map(c => c.visit(this, ctx))
    }
    abstract until(ctx: ToContext): boolean;
}


export class ToTabLayoutVisitor extends ToVisitor {
    packageName: string;
    until(): boolean {
        return isTabLayoutPage();
    }
    constructor(packageName: string) {
        super();
        this.packageName = packageName;
    }
    visitTextView(node: Ast, ctx: ToContext) {
        if (node.text === `退出直播间`) {
            if (node.parent && node.parent.clickable) {
                ctx.to = () => node.parent?.click()
                return;
            }
        }
        if (node.text === `退出`) {
            if (node.parent && node.parent.clickable) {
                ctx.to = () => node.parent?.click()
                return;
            }
        }
    }
    visitNode(node: Ast, ctx: ToContext) {
        if (node.className.endsWith(`TextView`)) {
            return this.visitTextView(node, ctx)
        }
        ctx.to = () => {
            back();
            sleep(1000 * 3)
        }
    }
}
const isRuning = (that?: any) => {
    if (!that) return true;
    if (that.isRuning) return that.isRuning();
    if (that.isExit) return false;
    return true;
}
export function toTabLayout(packageName: string = PACKAGES.KUAI_SHOU, max: number = 10, that?: any) {
    to(new ToTabLayoutVisitor(packageName), max, that)
    while (!isTabLayoutPage() && max > 0 && isRuning(that)) {
        back();
        sleep(1000 * 1)
        max -= 1;
    }
}

export class ToMyFollowVisitor extends ToVisitor {
    constructor(private pkg: string) {
        super()
    }
    visitNode(node: Ast, ctx: ToContext) {
        ctx.to = () => kwaiLiveMyFollow(this.pkg)
    }
    until(ctx: ToContext): boolean {
        return isMyFollowPage()
    }
}
export function toMyFollow(pkg: string = PACKAGES.KUAI_SHOU, max: number = 30, that?: any) {
    return to(new ToMyFollowVisitor(pkg), max, that)
}
export class ToMyFollowLiveRoomVisitor extends ToVisitor {
    visitRecyclerView(node: Ast, ctx: ToContext) {
        if (node.id.endsWith('live_my_follow_recycle_view')) {
            if (node.children.length > 0) {
                ctx.to = () => {
                    node.children[0].click()
                }
            }
        }
    }
    until(ctx: ToContext): boolean {
        return isLiveRoomPage()
    }
}
export function toMyFollowLiveRoom(max: number = 30, that?: any) {
    return to(new ToMyFollowLiveRoomVisitor(), max, that)
}

export class ToMineVisitor extends ToVisitor {
    // HorizontalScrollView
    visitHorizontalScrollView(node: Ast, ctx: ToContext) {
        if (node.sid === `tab_layout`) {
            const mine = node.findOne((it) => it.desc === `我` && it.clickable)
            if (mine) {
                ctx.to = () => mine.click()
                return;
            }
        }
        return node.children.map(it => it.visit(this, ctx))
    }
    until(): boolean {
        return isMinePage()
    }
}

export class ToMenuPageVisitor extends ToMineVisitor {
    visitImageButton(node: Ast, ctx: ToContext) {
        if (node.id.endsWith(`more_btn`) && node.desc === `更多` && node.visibleToUser && node.clickable) {
            ctx.to = () => node.click()
        }
        return node.children.map(it => it.visit(this, ctx))
    }
    until(): boolean {
        return isMenuPage()
    }
}

export class ToMineMoneyVisitor extends ToMenuPageVisitor {
    visitTextView(node: Ast, ctx: ToContext) {
        if (node.id.endsWith(`title`) && node.text === `我的钱包`) {
            if (node.parent && node.parent.clickable) {
                ctx.to = () => node.parent.click()
            }
        }
        return node.children.map(it => it.visit(this, ctx))
    }
    until(): boolean {
        return isMineMoneyPage()
    }
}

export class ToMineProfileVisitor extends ToMineVisitor {
    visitFrameLayout(node: Ast, ctx: ToContext) {
        if (isMineProfileAvatarUploadPage()) {
            back()
            return;
        }
        if (isMineProfileBgSettingPage()) {
            back()
            return;
        }
        if (isMineProfileBgSettingPage()) {
            back()
            return;
        }
        if (isMineProfileBgUploadPage()) {
            back()
            return;
        }
        if (isMineProfileNicknameSettingPage()) {
            back()
            return;
        }
        node.children.map(c => c.visit(this, ctx))
    }
    visitTextView(node: Ast, ctx: ToContext) {
        if (node.id.endsWith(`profile_settings_button`)) {
            ctx.to = () => node.parent.click()
        }
    }
    until(): boolean {
        return isMineProfilePage()
    }
}

export class ToMineProfileNicknameSettingVisitor extends ToMineProfileVisitor {
    visitTextView(node: Ast, ctx: ToContext): void {
        super.visitTextView(node, ctx)
        if (node.text === `昵称`) {
            ctx.to = () => node.parent.click()
        }
    }
    until(): boolean {
        return isMineProfileNicknameSettingPage()
    }
}

export class ToMineProfileAvatarSettingVisitor extends ToMineProfileVisitor {
    visitTextView(node: Ast, ctx: ToContext): void {
        super.visitTextView(node, ctx)
        if (node.text === `更换`) {
            ctx.to = () => node.parent.click()
        }
    }
    until(): boolean {
        return IsMineProfileAvatarSettingPage()
    }
}

export class ToMineProfileAvatarUploadVisitor extends ToMineProfileAvatarSettingVisitor {
    visitLinearLayout(node: Ast, ctx: ToContext) {
        if (node.id.endsWith(`avatar_choose_picture_container`)) {
            ctx.to = () => node.click()
        }
    }
    until(): boolean {
        return isMineProfileAvatarUploadPage()
    }
}




export class ToMineProfileBgSettingVisitor extends ToMineProfileVisitor {
    visitTextView(node: Ast, ctx: ToContext): void {
        super.visitTextView(node, ctx)
        if (node.text === `设置背景`) {
            ctx.to = () => node.parent.click()
        }
    }
    until(): boolean {
        return isMineProfileBgSettingPage()
    }
}


export class ToMineProfileBgUploadVisitor extends ToMineProfileBgSettingVisitor {
    visitLinearLayout(node: Ast, ctx: ToContext) {
        if (node.id.endsWith(`avatar_choose_picture_container`)) {
            ctx.to = () => node.click()
        }
    }
    until(): boolean {
        return isMineProfileAvatarUploadPage()
    }
}

export function toMineProfileBgUpload(max: number = 30, that?: any) {
    return to(new ToMineProfileBgUploadVisitor(), max, that)
}

export function toMineProfileBgSetting(max: number = 30, that?: any) {
    return to(new ToMineProfileBgSettingVisitor(), max, that)
}


export function toMineProfileAvatarUpload(max: number = 30, that?: any) {
    return to(new ToMineProfileAvatarUploadVisitor(), max, that)
}

export function toMineProfileAvatarSetting(max: number = 30, that?: any) {
    return to(new ToMineProfileAvatarSettingVisitor(), max, that)
}


export function toMineProfileNicknameSetting(max: number = 30, that?: any) {
    return to(new ToMineProfileNicknameSettingVisitor(), max, that)
}

export function toMineProfile(max: number = 30, that?: any) {
    return to(new ToMineProfileVisitor(), max, that)
}

export class ToHomeLiveVisitor extends ToVisitor {
    visitHorizontalScrollView(node: Ast, ctx: ToContext) {
        if (node.id.endsWith(`tab_layout`)) {
            const item = node.children.find(it => it.desc === `首页` && it.clickable)
            console.log(`home tab item is ${!!item}, is home page ${isHomePage()}, ${node.textTexts()}`)

            if (!isHomePage()) {
                ctx.to = () => item?.click()
                return;
            }
        }
        if (node.id.endsWith(`kcube_tab_strip`)) {
            const liveBtn = node.children.find(it => {
                return !!it.children.find(it => it.desc === `直播`)
            });
            if (liveBtn) {
                if (!isLiveSquarePage()) {
                    ctx.to = () => liveBtn?.click()
                    return;
                }
            } else {
                const liveBtn = node.children.find(it => {
                    return !!it.children.find(it => it.desc != `关注` && it.desc !== `同城` && it.desc !== '发现')
                });
                if (liveBtn) {
                    if (!isLiveSquarePage()) {
                        ctx.to = () => liveBtn?.click()
                    }
                    return;
                }
            }
        }
        return node.children.map(it => it.visit(this, ctx))
    }
    visitTextView(node: Ast, ctx: ToContext) {
        if (node.id.endsWith(`textView`) && node.text === `直播`) {
            if (!isLiveSquarePage()) {
                ctx.to = () => node.parent?.click()
            }
        }
    }
    until(ctx: ToContext): boolean {
        return isLiveSquarePage();
    }
}

export class ToHomeFollowVisitor extends ToVisitor {
    visitHorizontalScrollView(node: Ast, ctx: ToContext) {
        if (node.id.endsWith(`tab_layout`)) {
            const item = node.children.find(it => it.desc === `首页` && it.clickable)
            if (!isHomePage()) {
                ctx.to = () => item.click()
            }
        }
        return node.children.map(it => it.visit(this, ctx))
    }
    visitView(node: Ast, ctx: ToContext) {
        if (node.id.endsWith(`follow_tab_text`) && node.desc === `关注`) {
            if (!isHomeFollowPage()) {
                ctx.to = () => node.parent.click()
            }
        }
    }
    until(): boolean {
        return isHomeFollowPage();
    }
}

export class ToFirstFollowLiveVisitor extends ToHomeFollowVisitor {
    visitRecyclerView(node: Ast, ctx: ToContext) {
        if (node.id.endsWith(`pymi_users_list`)) {
            const item = node.children.find(it => it.clickable && it.id.endsWith(`pymi_user_container`))
            if (item) {
                ctx.to = () => item.click()
            }
        }
        return node.children.map(it => it.visit(this, ctx))
    }
    until(): boolean {
        return isLiveRoomPage()
    }
}


export class ToFirstLiveSqueareVisitor extends ToHomeLiveVisitor {
    visitRecyclerView(node: Ast, ctx: ToContext) {
        if (node.id.endsWith('live_explore_fragment_recycler_view')) {
            const item = node.children.find(it => it.id.endsWith(`live_explore_feed_card_layout`) && it.clickable)
            if (item) {
                if (!isLiveRoomPage()) {
                    ctx.to = () => item.click()
                }
            }
        }
        return node.children.map(it => it.visit(this, ctx))
    }
    until(ctx: ToContext): boolean {
        return isLiveRoomPage()
    }
}

/**
 * 

<android.widget.FrameLayout visible="true">
    <android.widget.LinearLayout visible="true">
        <android.widget.FrameLayout visible="true">
            <android.widget.ImageView id="com.smile.gifmaker:id/photo" clickable="true" visible="true">
            </android.widget.ImageView>
            <android.widget.ImageView id="com.smile.gifmaker:id/close" clickable="true" visible="true">
            </android.widget.ImageView>
        </android.widget.FrameLayout>
        <android.widget.LinearLayout visible="true">
            <android.widget.ImageView id="com.smile.gifmaker:id/avatar" clickable="true" visible="true">
            </android.widget.ImageView>
            <android.widget.TextView id="com.smile.gifmaker:id/title" text="鞋子小雪的直播" visible="true">
            </android.widget.TextView>
        </android.widget.LinearLayout>
        <android.widget.Button id="com.smile.gifmaker:id/action" text="进入直播间" clickable="true" visible="true">
        </android.widget.Button>
        <android.widget.TextView id="com.smile.gifmaker:id/source" text="分享者@局CF人" clickable="true" visible="true">
        </android.widget.TextView>
    </android.widget.LinearLayout>
</android.widget.FrameLayout>
 */
/**
 * 
<android.widget.FrameLayout visible="true">
    <android.widget.LinearLayout visible="true">
        <android.widget.FrameLayout visible="true">
            <android.widget.ImageView id="com.smile.gifmaker:id/photo" clickable="true" visible="true">
            </android.widget.ImageView>
            <android.widget.ImageView id="com.smile.gifmaker:id/close" clickable="true" visible="true">
            </android.widget.ImageView>
        </android.widget.FrameLayout>
        <android.widget.LinearLayout visible="true">
            <android.widget.ImageView id="com.smile.gifmaker:id/avatar" clickable="true" visible="true">
            </android.widget.ImageView>
            <android.widget.TextView id="com.smile.gifmaker:id/title" text="3D龙飞【第四个号】" visible="true">
            </android.widget.TextView>
        </android.widget.LinearLayout>
        <android.widget.Button id="com.smile.gifmaker:id/action" text="暂未直播，去个人主页" clickable="true" visible="true">
        </android.widget.Button>
        <android.widget.TextView id="com.smile.gifmaker:id/source" text="分享者@彻彻底底是" clickable="true" visible="true">
        </android.widget.TextView>
    </android.widget.LinearLayout>
</android.widget.FrameLayout>
 */
export class JoinLiveRoomVisitor extends ToVisitor {
    visitButton(node: Ast, ctx: ToContext) {
        if (node.id.endsWith(`action`) && node.text === `进入直播间`) {
            if (!isLiveRoomPage()) {
                ctx.to = () => node.click()
                return;
            }
        }
        // 意外情况 主播下播
        if (node.id.endsWith(`action`) && node.text === `暂未直播，去个人主页`) {
            if (!isLiveRoomPage()) {
                ctx.to = () => back()
                return;
            }
        }
    }
    until(): boolean {
        return isLiveRoomPage()
    }
}

export class ToHomeJingXuanVisitor extends ToVisitor {
    selected: string;
    visitActionBar$c(node: Ast, ctx: ToContext) {
        if (node.selected) {
            this.selected = node.desc;
        }
        if (node.desc === `精选`) {
            if (node.packageName === PACKAGES.KUAI_SHOU) {
                ctx.to = () => node.click()
                sleep(1000 * 3)
                return;
            }
        }
        if (node.desc === '首页') {
            if (node.packageName === PACKAGES.KUAI_SHOU_Nebula) {
                ctx.to = () => node.click()
                sleep(1000 * 3)
                return;
            }
        }
    }
    visitView(node: Ast, ctx: ToContext) {
        if (node.desc === `发现`) {
            if (node.packageName === PACKAGES.KUAI_SHOU_Nebula) {
                ctx.to = () => node.parent.click()
                sleep(1000 * 3)
                return;
            }
        }
    }
    until(ctx: ToContext): boolean {
        const isHomeJx = isHomeJingXuanPage()
        return isHomeJx;
    }
}

export function toHomeJingXuan(max: number = 30, that?: any) {
    return to(new ToHomeJingXuanVisitor(), max, that)
}


export function toJoinLiveRoom(max: number = 30, that?: any) {
    return to(new JoinLiveRoomVisitor(), max, that)
}

export function toHomeLive(max: number = 30, that?: any) {
    return to(new ToHomeLiveVisitor(), max, that)
}
export function toFirstHomeLive(max: number = 30, that?: any) {
    return to(new ToFirstLiveSqueareVisitor(), max, that)
}

export function toFirstFoolowLive(max: number = 30, that?: any) {
    return to(new ToFirstFollowLiveVisitor(), max, that)
}

export function toHomeFollow(max: number = 30, that?: any) {
    return to(new ToHomeFollowVisitor(), max, that)
}

export function toMineMoney(max: number = 30, that?: any) {
    return to(new ToMineMoneyVisitor(), max, that)
}

export function toMine(max: number = 5, that?: any) {
    return to(new ToMineVisitor(), max, that)
}


export class ToSettingPage extends ToVisitor {
    visitTextView(node: Ast, ctx: ToContext) {
        if (node.sid === `title` && node.text === `设置` && node.parent.sid === `bottom_right`) {
            ctx.to = () => node.parent.click()
            return;
        }
        if (node.sid === `tab_settings` && node.text === `设置`) {
            if (node.parent.sid === `tab_settings`) {
                ctx.to = () => node.parent.click()
                return;
            }
        }
    }
    visitViewGroup(node: Ast, ctx: ToContext) {
        if (node.sid === `tab_settings`) {
            ctx.to = () => node.click()
            return;
        }
        node.children.map(c => c.visit(this, ctx))
    }
    visitImageButton(node: Ast, ctx: ToContext) {
        if (node.sid === `more_btn` && node.desc === `更多`) {
            ctx.to = () => node.click()
            return;
        }
    }
    visitFrameLayout(node: Ast, ctx: ToContext) {
        if (node.sid === `featured_left_hamburger`) {
            ctx.to = () => node.click()
            toastLog(`找到更多按钮`)
            return;
        }
        if (node.sid === `left_btn`) {
            ctx.to = () => node.click()
            toastLog(`找到更多按钮`)
            return;
        }
        node.children.map(c => c.visit(this, ctx))
    }
    until(ctx: ToContext): boolean {
        return isSettingPage()
    }
}

export function toSettingPage(max: number = 10, that?: any) {
    return to(new ToSettingPage(), max, that)
}

class ToSettingCachePage extends ToVisitor {
    visitNode(node: Ast, ctx: ToContext) {
        super.visitNode(node, ctx)
    }
    visitTextView(node: Ast, ctx: ToContext) {
        if (node.sid === `item_title` && node.text === `存储空间`) {
            toastLog(`找到存储空间`)
            const n = node.parent;
            ctx.to = () => n.click()
            return;
        }
    }
    visitRecyclerView(node: Ast, ctx: ToContext) {
        if (node.sid === `item_list`) {
            ctx.up = () => node.scrollUp()
        }
        node.children.map(c => c.visit(this, ctx))
    }
    until(ctx: ToContext): boolean {
        return isSettingCachePage();
    }
}

export function toSettingCachePage(max: number = 16, that?: any) {
    return to(new ToSettingCachePage(), max, that)
}

export function to(visitor: ToVisitor, max: number = 60 * 3, that?: any) {
    let ctx: ToContext = {};
    const root = createRootAst()
    root.visit(visitor, ctx)
    let changeCount: number = 0;
    while (!visitor.until(ctx) && max > 0 && isRuning(that)) {
        const root = createRootAst()
        root.visit(visitor, ctx)
        tryRun(() => {
            if (ctx.to) {
                ctx.to()
                ctx.to = undefined;
            }
            if (changeCount >= 5) {
                ctx.up && ctx.up()
                changeCount = 0;
            }
        })
        max -= 1;
        changeCount += 1;
        sleep(1000)
        if (visitor.until(ctx)) {
            break;
        }
    }
    return ctx;
}
